package chatclient.netio;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.util.Vector;
import javax.swing.SwingUtilities;

public class Connection {

    public Connection(String s, int i, ConnectionListener connectionlistener)
            throws Exception {
        pingTime = 0x1d4c0;
        listener = connectionlistener;
        host = s;
        port = i;
        cmdQueue = new Vector();
        socket = new Socket(host, port);
        AttrList attrlist = new AttrList();
        pingCmd = (new Command(Command.PING, attrlist)).getByteCache(true);
        readerThread = new Thread(new Runnable() {

            @Override
            public void run() {
                reader();
            }
        });
        readerThread.start();
        writerThread = new Thread(new Runnable() {

            @Override
            public void run() {
                writer();
            }
        });
        writerThread.start();
    }

    public String getHost() {
        return host;
    }

    public int getPort() {
        return port;
    }

    protected void close() {
        if (!close) {

            try {
                if (socket != null) {
                    socket.close();
                }
                socket = null;
            } catch (Exception exception) {
                //exception.printStackTrace();
            }
            try {
                listener.connectionClosed();
            } catch (Exception exception1) {
                exception1.printStackTrace();
            }
            close = true;
        }
    }

    protected boolean isClosed() {
        return close;
    }

    public void destroy() {
        close();
        while (readerThread != null && readerThread != Thread.currentThread() && readerThread.isAlive()) {
            try {
                readerThread.interrupt();
                readerThread.join();
            } catch (InterruptedException interruptedexception) {
            }
        }
        while (writerThread != null && writerThread != Thread.currentThread() && writerThread.isAlive()) {
            try {
                writerThread.interrupt();
                writerThread.join();
            } catch (InterruptedException interruptedexception1) {
            }
        }
    }

    public void waitForCmd()
            throws Exception {
        synchronized (cmdQueue) {
            for (; cmdQueue.isEmpty(); cmdQueue.wait()) {
            }
        }
    }

    public byte[] getCmd()
            throws Exception {
        byte[] abyte0;
        synchronized (this.cmdQueue) {
            while (this.cmdQueue.isEmpty()) {
                try {
                    this.cmdQueue.wait(this.pingTime);
                } catch (InterruptedException interruptedexception) {
                    //interruptedexception.printStackTrace();
                }
                if (this.cmdQueue.isEmpty()) {
                    byte[] abyte1 = this.pingCmd;
                    return abyte1;
                }
            }
            abyte0 = (byte[]) this.cmdQueue.elementAt(0);
            this.cmdQueue.removeElementAt(0);
        }

        return abyte0;
    }

    public byte[] tryCmd()
            throws Exception {
        byte abyte0[];
        synchronized (cmdQueue) {
            if (cmdQueue.isEmpty()) {
                abyte0 = (byte[]) null;
            } else {
                abyte0 = (byte[]) cmdQueue.elementAt(0);
                cmdQueue.removeElementAt(0);
            }
        }
        return abyte0;
    }

    public void sendCommand(Command command)
            throws Exception {

        System.out.println("ADZ - Connection.java(Client side)->sendCommand::"+command);
        synchronized (cmdQueue) {
            cmdQueue.addElement(command.getByteCache(true));
            System.out.println("ADZ - Connection.java->sendCommand: cmdQueue is about to notify");
            cmdQueue.notify();
        }
    }

    private void reader() {
        try {
            BufferedInputStream bufferedinputstream = new BufferedInputStream(socket.getInputStream());
            while (!isClosed()) {
                final Event event = new Event(bufferedinputstream);

                try {
                    SwingUtilities.invokeAndWait(new Runnable() {

                        @Override
                        public void run() {
                            listener.doEvent(event);
                        }
                    });
                } catch (InvocationTargetException ex) {
                    ex.getTargetException().printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                    System.err.println("listener.doEvent() didn't complete successfully");
                }

            }
        } catch (Exception ex2) {
            //ex2.printStackTrace();
            close();
        }
    }

    private void writer() {
        try {
            BufferedOutputStream bufferedoutputstream = new BufferedOutputStream(socket.getOutputStream());
            for (; !isClosed(); bufferedoutputstream.flush()) {
                byte abyte0[] = getCmd();
                bufferedoutputstream.write(abyte0);
                while ((abyte0 = tryCmd()) != null) {
                    bufferedoutputstream.write(abyte0);
                }
            }

        } catch (Exception exception) {
            //exception.printStackTrace();
            close();
        }
    }
    private Socket socket;
    private int pingTime;
    private byte pingCmd[];
    private String host;
    private int port;
    private final Vector cmdQueue;
    private Thread readerThread;
    private Thread writerThread;
    private boolean close;
    private ConnectionListener listener;
}
